package com.bsj.power.pls.config.net.netty.common.client;

import com.bsj.power.common.util.Conv;
import com.bsj.tools.HexStr;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;

/**
 * @author yinhao
 * @version 1.0
 * @description 分包
 * @date 2024/10/17
 */
@Slf4j
public class RTKDecode extends ByteToMessageDecoder {

    /**
     * 标识位(2) + 长度(1) + 校验(3)
     **/
    private static final int PACK_MIN_LEN = 6;

    public RTKDecode() {}

    @Override
    protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf in, List<Object> out) throws Exception {
        //有多少字节可以读
        int len = in.readableBytes();
        //转为数组
        byte[] data = new byte[len];
        in.getBytes(in.readerIndex(), data);
        //数据格式RTCM3.2,最少6个字节起。参考：https://blog.csdn.net/meishujian/article/details/133642359
        if (len < PACK_MIN_LEN) {
            //最少应不少于230字节
            return;
        }
        //正确包
        List<Object> OKList = new ArrayList<>();
        int lastOnIndex = analysisPacket(OKList, data);
        in.readBytes(lastOnIndex).release();
        out.addAll(OKList);
        int unLen = len - lastOnIndex;
        if(unLen == 0){
            in.readBytes(in.readableBytes()).release();
            return;
        }
        if (unLen == 1) {
            return;
        }
        //找包头
        int posHead = getPosHead(data, lastOnIndex);
        if (posHead < 0 && lastOnIndex < len) {
            byte[] arr = new byte[unLen];
            System.arraycopy(data, lastOnIndex, arr, 0, unLen);
            log.info("[RTK BROADCAST]错误数据： {}", HexStr.toStr(arr));
            in.readBytes(in.readableBytes()).release();
            return;
        }
        if (len - posHead < PACK_MIN_LEN) {
            return;
        }
        if (unLen > 0 && unLen < 2048) {
            return;
        } else {
            try {
                byte[] arr = new byte[unLen];
                System.arraycopy(data, posHead, arr, 0, unLen);
                in.readBytes(in.readableBytes()).release();
                return;
            } catch (Exception e) {
                log.error("[RTK BROADCAST]原始数据错误: {}", HexStr.toStr(data));
                return;
            }

        }
    }

    /**
     * 解包
     * @param OKList
     * @param data
     * @return
     */
    public static int analysisPacket(List<Object> OKList, byte[] data) {
        int len = data.length;
        //每包都有最小长度限制
        if (len < PACK_MIN_LEN) {
            return 0;
        }
        // 未解析完数据索引
        int lastOkIndex = 0;
        int offset = 0;
        while (offset < len) {
            //从头开始找
            int posHead = getPosHead(data, offset);
            if (posHead < 0) {
                //没有包头
                return lastOkIndex;
            }
            if (len - posHead < PACK_MIN_LEN) {
                return lastOkIndex;
            }
            //0xD3
            offset = posHead + 1;
            //2字节长度
//            int bodyLen = Byte.toUnsignedInt(data[offset]);
            int bodyLen = Conv.getShortNetOrder(data, offset);
            offset += 2;
            int dataLen = 1 + 2 + bodyLen + 3;
            //计算包尾的位置大于数据的长度，重新找
            if (dataLen + offset - 3 > len) {
                return lastOkIndex;
            }
            //校验
            byte[] array = new byte[dataLen];
            System.arraycopy(data, posHead, array, 0, dataLen);
            OKList.add(array);
            offset += bodyLen + 3;
            lastOkIndex = offset;
        }
        return lastOkIndex;
    }

    /**
     * 找包头
     * @param data
     * @param offset
     * @return
     */
    public static int getPosHead(byte[] data, int offset) {
        int posHead = -1;
        int length = data.length;
        if (offset >= length) {
            return posHead;
        }

        for (int i = offset; i < data.length; i++) {
            byte tem = data[i];
            if (i == data.length -1) {
                break;
            }
            byte tem1 = data[i + 1];
            if (tem == (byte) 0xD3) {
//                if (tem1 == 0x0 || tem1 == 0x1) {
                    posHead = i;
                    break;
//                }
            }
        }
        return posHead;
    }
}
